#ifndef MODEL_CC
#define MODEL_CC
#include<string>
#include<fstream>
#include<sstream>
#include<iostream>
#include<algorithm>
#include<iterator>
#include<vector>
#include<map>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include "def.hpp"
#include "io.hpp"
#include "log.hpp"
#include "utils.hpp"
#include "topicmodel.hpp"
#include "topicmodel_getmodel.hpp"

using namespace std;

namespace Puza{
  int TopicModel(){
    GenericTopicModel* topic_model = getTopicModel();
    if(PuzaDEF::Instance()->currentTopicModelTaskType == TOPICMODEL_TASK_INFERENCE){
      int ProcessedDOCS = 0;
      while(1){
	int remain = topic_model->GetDocuments(0);
	if(topic_model->TM_DOCS.size()!=0){
	  PuzaLogger::Instance()->PutString("Read " +  to_string<int>(topic_model->TM_DOCS.size(),std::dec) + " Documents.");
	  topic_model->Inference();
	  ProcessedDOCS += topic_model->TM_DOCS.size();
	  PuzaLogger::Instance()->PutString("Totally Processed " +  to_string<int>(ProcessedDOCS,std::dec) + " Documents.");
	}
	if(remain == 0)
	  break;
      }
      topic_model->SaveModel();
    }
    else if(PuzaDEF::Instance()->currentTopicModelTaskType == TOPICMODEL_TASK_INFERENCE_AND_PREDICTION){
      // we first do inference
      PuzaLogger::Instance()->PutString("============= Training Phase ================");
      int ProcessedDOCS = 0;
      PuzaDEF::Instance()->input_file_name = PuzaDEF::Instance()->train_file_name;
      while(1){
	int remain = topic_model->GetDocuments(0);
	if(topic_model->TM_DOCS.size()!=0){
	  PuzaLogger::Instance()->PutString("Read " +  to_string<int>(topic_model->TM_DOCS.size(),std::dec) + " Documents.");
	topic_model->Inference();
	ProcessedDOCS += topic_model->TM_DOCS.size();
	PuzaLogger::Instance()->PutString("Totally Processed " +  to_string<int>(ProcessedDOCS,std::dec) + " Documents.");
	}
	if(remain == 0)
	  break;
      }
      topic_model->SaveModel();
      // we then do prediction
      // readjust to online model
      PuzaLogger::Instance()->PutString("============= Testing Phase ================");
      ProcessedDOCS = 0;
      PuzaDEF::Instance()->input_file_name = PuzaDEF::Instance()->test_file_name;
      topic_model->GetDocuments(1);
      if(topic_model->TM_DOCS.size()!=0){
	PuzaLogger::Instance()->PutString("Read " +  to_string<int>(topic_model->TM_DOCS.size(),std::dec) + " Documents.");
	topic_model->Prediction();
	ProcessedDOCS += topic_model->TM_DOCS.size();  
	PuzaLogger::Instance()->PutString("Totally Processed " +  to_string<int>(ProcessedDOCS,std::dec) + " Documents.");
      }
    }
    else if(PuzaDEF::Instance()->currentTopicModelTaskType == TOPICMODEL_TASK_INTERACTIVE){
      PuzaLogger::Instance()->PutString("============= Interactive Trainig and Testing ================");
      int ProcessedDOCS = 0;
      PuzaDEF::Instance()->input_file_name = PuzaDEF::Instance()->train_file_name;
      topic_model->GetDocuments(0);
      PuzaDEF::Instance()->input_file_name = PuzaDEF::Instance()->test_file_name;
      if(topic_model->TM_DOCS.size()!=0){
	PuzaLogger::Instance()->PutString("Read " +  to_string<int>(topic_model->TM_DOCS.size(),std::dec) + " Documents.");
	ProcessedDOCS += topic_model->TM_DOCS.size();
	PuzaLogger::Instance()->PutString("Totally Processed " +  to_string<int>(ProcessedDOCS,std::dec) + " Documents.");
	topic_model->Interactive();
      }
      topic_model->SaveModel();
    }
    delete topic_model;
    return 0;
  }
};

#endif
